//
//  PMSpace.h
//  PezMonkey
//
//  Created by Spence DiNicolantonio on 11/2/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "PMCore.h"
#import "PMShape.h"

@class PMBody, PMConstraint, PMCollision;


@interface PMSpace : NSObject {
@protected
	// Chipmunk space reference
	cpSpace *space;
	
@private
	// Set of rigid bodies in the space
	NSMutableArray *bodies;
	
	// Set of active collision shapes in the space
	NSMutableArray *activeShapes;
	
	// Set of static collision shapes in the space
	NSMutableArray *staticShapes;
	
	// Set of constraints in the space
	NSMutableArray *constraints;
	
	// The number of simulation steps to take for any given time interval
	NSUInteger subSteps;
	
	// List of collision callbacks
	NSMutableDictionary *collisionCallbacks;
	
	// Set of post step callbacks
	NSMutableArray *postStepCallbacks;
	
	// Indicates whether pass-through is enabled
	BOOL passThroughEnabled;
	
	// Dictionary of all shapes and all shapes passing through them
	NSMutableDictionary *passingShapes;
	
	// User defined data pointer
	id data;
}

@property (assign) NSUInteger subSteps;
@property (assign) BOOL passThroughEnabled;
@property (nonatomic, retain) id data;

// Property definitions of getters/setters for data members stored by backend 
// Chipmunk structure. These properties are not synthesized, because their 
// implementations are given explicitly.
@property (assign, readonly) cpSpace *cpSpace;
@property (assign) NSUInteger iterations;
@property (assign) NSUInteger elasticIterations;
@property (assign) PMVect gravity;
@property (assign) PMFloat damping;
@property (assign, readonly) NSUInteger steps;
@property (nonatomic, readonly) NSArray *bodies;
@property (nonatomic, readonly) NSArray *shapes;
@property (nonatomic, readonly) NSArray *activeShapes;
@property (nonatomic, readonly) NSArray *staticShapes;
@property (nonatomic, readonly) NSArray *allShapes;
@property (nonatomic, readonly) NSArray *constraints;
@property (nonatomic, readonly) NSArray *collisions;


#pragma mark Init
- (id)initWithGravity:(PMVect)gravity;

#pragma mark Convenience
+ (PMSpace *)space;
+ (PMSpace *)spaceWithGravity:(PMVect)gravity;


#pragma mark -
#pragma mark Add Elements
- (PMBody *)addBody:(PMBody *)body;
- (PMShape *)addShape:(PMShape *)shape isStatic:(BOOL)isStatic;
- (PMShape *)addShape:(PMShape *)shape;
- (PMShape *)addActiveShape:(PMShape *)shape;
- (PMShape *)addStaticShape:(PMShape *)shape;
- (PMConstraint *)addConstraint:(PMConstraint *)constraint;


#pragma mark -
#pragma mark Remove Elements
- (void)removeBody:(PMBody *)body;
- (void)removeShape:(PMShape *)shape;
- (void)removeShapeAndBody:(PMShape *)shape;
- (void)removeConstraint:(PMConstraint *)constraint;
- (void)removeAllBodies;
- (void)removeAllShapes;
- (void)removeAllConstraints;
- (void)removeAll;


#pragma mark -
#pragma mark Queries
- (BOOL)containsBody:(PMBody *)body;
- (BOOL)containsShape:(PMShape *)shape;
- (BOOL)containsActiveShape:(PMShape *)shape;
- (BOOL)containsStaticShape:(PMShape *)shape;
- (BOOL)containsConstraint:(PMConstraint *)constraint;
- (BOOL)isShape:(PMShape *)shapeA passingThroughShape:(PMShape *)shapeB;
- (PMShape *)shapeAtPoint:(PMVect)point;
- (PMShape *)shapeAtPoint:(PMVect)point layers:(PMLayerMask)layers group:(PMCollisionGroup)group;
- (PMShape *)shapeOnSegment:(PMSegment)segment info:(PMSegmentCollisionInfo *)info;
- (PMShape *)shapeOnSegment:(PMSegment)segment layers:(PMLayerMask)layers group:(PMCollisionGroup)group info:(PMSegmentCollisionInfo *)info;


#pragma mark -
#pragma mark Spacial Hash
- (void)setActiveHashSize:(NSUInteger)size cellDimension:(PMFloat)cellDimension;
- (void)setStaticHashSize:(NSUInteger)size cellDimension:(PMFloat)cellDimension;
- (void)rehashStatic;


#pragma mark -
#pragma mark Collision Callbacks
- (void)registerDefaultCollisionCallbackTarget:(id)target selector:(SEL)selector;
- (void)removeDefaultCollisionCallback;
- (void)registerCollisionCallbackTarget:(id)target selector:(SEL)selector forTypeA:(PMCollisionType)typeA typeB:(PMCollisionType)typeB;
- (void)removeCollisionCallbackForTypeA:(PMCollisionType)typeA typeB:(PMCollisionType)typeB;


#pragma mark -
#pragma mark Post Step Callbacks
- (void)registerPostStepCallbackTarget:(id)target selector:(SEL)selector userData:(id)userData;
- (void)postStepRemoveBody:(PMBody *)body;
- (void)postStepRemoveShape:(PMShape *)shape;
- (void)postStepRemoveConstraint:(PMConstraint *)constraint;
- (void)postStepRemoveShapeAndBody:(PMShape *)shape;


#pragma mark -
#pragma mark Step
- (void)step:(NSTimeInterval)deltaT;

@end



#pragma mark -
#pragma mark Functions
static BOOL PMSpaceHandleCollision(PMCollision *collision);
static BOOL PMSpaceChipmunkCollisionCallbackBegin(cpArbiter *arb, struct cpSpace *sp, void *data);
static BOOL PMSpaceChipmunkCollisionCallbackPreSolve(cpArbiter *arb, struct cpSpace *sp, void *data);
static void PMSpaceChipmunkCollisionCallbackPostSolve(cpArbiter *arb, struct cpSpace *sp, void *data);
static void PMSpaceChipmunkCollisionCallbackSeparate(cpArbiter *arb, struct cpSpace *sp, void *data);